package REST;

import com.google.gson.Gson;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

/**
 * REST Web Service
 *
 * @author Maarten
 */
@Path("REST")
public class RESTResource {

    @Context
    private UriInfo context;
    private Connection con;
    private Gson g;

    public RESTResource() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mycinema", "root", "");
            g = new Gson();
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException ex) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Path("/film/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String getFilm(@PathParam("id") String id) {
        try {
            ResultSet rs;
            Film f;

            CallableStatement s = con.prepareCall("CALL getFilm(?)");
            s.setString(1, id);

            rs = s.executeQuery();

            if (rs.next()) {
                f = new Film();
                f.setFilm_ID(rs.getString("Film_ID"));
                f.setTitel(rs.getString("Titel"));
                f.setJaar(rs.getString("Jaar"));
                f.setLooptijd(rs.getString("Looptijd"));
                f.setKorteInhoud(rs.getString("KorteInhoud"));
                f.setAfbeelding(rs.getString("Afbeelding"));
                f.setStudio(rs.getString("Studio"));
                f.setGenre1(rs.getString("Genre1"));
                f.setGenre2(rs.getString("Genre2"));
                f.setStream_url(rs.getString("Stream_url"));
                f.setPrijs(rs.getString("Prijs"));
                f.setKortingPercentage(rs.getString("KortingPercentage"));

                return g.toJson(f);
            }
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, e.getMessage());
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        return null;
    }

    @Path("/films")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String getFilms() {
        try {
            ArrayList<Film> films = new ArrayList<Film>();
            Film f;
            ResultSet rs;

            CallableStatement s = con.prepareCall("CALL getFilms");
            rs = s.executeQuery();

            while (rs.next()) {
                f = new Film();

                f.setFilm_ID(rs.getString("Film_ID"));
                f.setTitel(rs.getString("Titel"));
                f.setJaar(rs.getString("Jaar"));
                f.setLooptijd(rs.getString("Looptijd"));
                f.setKorteInhoud(rs.getString("KorteInhoud"));
                f.setAfbeelding(rs.getString("Afbeelding"));
                f.setStudio(rs.getString("Studio"));
                f.setGenre1(rs.getString("Genre1"));
                f.setGenre2(rs.getString("Genre2"));
                f.setStream_url(rs.getString("Stream_url"));
                f.setPrijs(rs.getString("Prijs"));
                f.setKortingPercentage(rs.getString("KortingPercentage"));

                films.add(f);
            }

            return g.toJson(films);

        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
    }

    @Path("/films/top5")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String GetTop5Films() {
        try {
            ArrayList<Film> films = new ArrayList<Film>();
            Film f;
            ResultSet rs;

            CallableStatement s = con.prepareCall("CALL getTop5Films");
            rs = s.executeQuery();

            while (rs.next()) {
                f = new Film();

                f.setFilm_ID(rs.getString("Film_ID"));
                f.setTitel(rs.getString("Titel"));
                f.setJaar(rs.getString("Jaar"));
                f.setLooptijd(rs.getString("Looptijd"));
                f.setKorteInhoud(rs.getString("KorteInhoud"));
                f.setAfbeelding(rs.getString("Afbeelding"));
                f.setStudio(rs.getString("Studio"));
                f.setGenre1(rs.getString("Genre1"));
                f.setGenre2(rs.getString("Genre2"));
                f.setStream_url(rs.getString("Stream_url"));
                f.setPrijs(rs.getString("Prijs"));
                f.setKortingPercentage(rs.getString("KortingPercentage"));

                films.add(f);
            }

            return g.toJson(films);

        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
    }

    @Path("/film/search/{titel}")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String searchFilm(@PathParam("titel") String titel) {
        try {
            ArrayList<Film> films = new ArrayList<Film>();
            Film f;
            ResultSet rs;

            CallableStatement s = con.prepareCall("CALL searchFilm(?)");
            s.setString(1, titel);

            rs = s.executeQuery();

            while (rs.next()) {
                f = new Film();

                f.setFilm_ID(rs.getString("Film_ID"));
                f.setTitel(rs.getString("Titel"));
                f.setJaar(rs.getString("Jaar"));
                f.setLooptijd(rs.getString("Looptijd"));
                f.setKorteInhoud(rs.getString("KorteInhoud"));
                f.setAfbeelding(rs.getString("Afbeelding"));
                f.setStudio(rs.getString("Studio"));
                f.setGenre1(rs.getString("Genre1"));
                f.setGenre2(rs.getString("Genre2"));
                f.setStream_url(rs.getString("Stream_url"));
                f.setPrijs(rs.getString("Prijs"));
                f.setKortingPercentage(rs.getString("KortingPercentage"));

                films.add(f);
            }

            return g.toJson(films);

        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
    }

    @Path("/film/{id}/commentaar")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String getCommentaarForFilm(@PathParam("id") String id) {
        try {
            ResultSet rs;
            ArrayList<Commentaar> comments = new ArrayList<Commentaar>();

            CallableStatement s = con.prepareCall("CALL getCommentaarForFilm(?)");
            s.setString(1, id);

            rs = s.executeQuery();

            while (rs.next()) {
                Commentaar c = new Commentaar();
                c.setGebruiker_ID(rs.getString("Gebruiker_ID"));
                //c.setFilm_ID(rs.getString("Film_ID"));
                c.setCommentaar_ID(rs.getString("Commentaar"));
                c.setDatum(rs.getString("Datum"));

                comments.add(c);
            }

            return g.toJson(comments);

        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return "Error";
    }

    @Path("/film/{id}/url")
    @Produces(MediaType.TEXT_PLAIN)
    @GET
    public String getStream(@PathParam("id") String id) {
        try {
            ResultSet rs;
            String stream_url = "";

            CallableStatement s = con.prepareCall("CALL getStream(?)");
            s.setString(1, id);

            rs = s.executeQuery();

            if (rs.next()) {
                stream_url = rs.getString("stream_url");
            }

            return stream_url;

        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return "Error";
    }

    @Path("/film/aanbiedingen")
    @Produces(MediaType.TEXT_PLAIN)
    @GET
    public String getAanbiedingen() {
        try {
            ArrayList<Film> films = new ArrayList<Film>();
            Film f;
            ResultSet rs;

            CallableStatement s = con.prepareCall("CALL getAanbiedingen");

            rs = s.executeQuery();

            while (rs.next()) {
                f = new Film();

                f.setFilm_ID(rs.getString("Film_ID"));
                f.setTitel(rs.getString("Titel"));
                f.setJaar(rs.getString("Jaar"));
                f.setLooptijd(rs.getString("Looptijd"));
                f.setKorteInhoud(rs.getString("KorteInhoud"));
                f.setAfbeelding(rs.getString("Afbeelding"));
                f.setStudio(rs.getString("Studio"));
                f.setGenre1(rs.getString("Genre1"));
                f.setGenre2(rs.getString("Genre2"));
                f.setStream_url(rs.getString("Stream_url"));
                f.setPrijs(rs.getString("Prijs"));
                f.setKortingPercentage(rs.getString("KortingPercentage"));

                films.add(f);
            }

            return g.toJson(films);
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException ex) {
                    Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return "False";
    }

    @Path("/gebruiker/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String getGebruiker(@PathParam("id") String id) {
        try {
            ResultSet rs;
            Gebruiker gebruiker;

            CallableStatement s = con.prepareCall("CALL getGebruiker(?)");
            s.setString(1, id);

            rs = s.executeQuery();

            if (rs.next()) {
                gebruiker = new Gebruiker();

                gebruiker.setGebruiker_ID(rs.getString("Gebruiker_ID"));
                gebruiker.setVoornaam(rs.getString("Voornaam"));
                gebruiker.setAchternaam(rs.getString("Achternaam"));
                gebruiker.setEmail(rs.getString("Email"));
                gebruiker.setGeboortedatum(rs.getString("Geboortedatum"));
                gebruiker.setWachtwoord_hash(rs.getString("Wachtwoord_hash"));
                gebruiker.setSalt(rs.getString("Salt"));

                return g.toJson(gebruiker);
            }
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
    }

    @Path("/gebruiker/{id}/films")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String getFilmFromGebruiker(@PathParam("id") String id) {
        try {
            ArrayList<Film> films = new ArrayList<Film>();
            Film f;
            ResultSet rs;

            CallableStatement s = con.prepareCall("CALL getFilmsFromGebruiker(?)");
            s.setString(1, id);

            rs = s.executeQuery();

            while (rs.next()) {
                f = new Film();

                f.setFilm_ID(rs.getString("Film_ID"));
                f.setTitel(rs.getString("Titel"));
                f.setJaar(rs.getString("Jaar"));
                f.setLooptijd(rs.getString("Looptijd"));
                f.setKorteInhoud(rs.getString("KorteInhoud"));
                f.setAfbeelding(rs.getString("Afbeelding"));
                f.setStudio(rs.getString("Studio"));
                f.setGenre1(rs.getString("Genre1"));
                f.setGenre2(rs.getString("Genre2"));
                f.setStream_url(rs.getString("Stream_url"));
                f.setPrijs(rs.getString("Prijs"));
                f.setKortingPercentage(rs.getString("KortingPercentage"));

                films.add(f);
            }

            return g.toJson(films);

        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
    }

    @Path("/gebruiker")
    @Consumes(MediaType.APPLICATION_JSON)
    //@Produces(MediaType.TEXT_PLAIN)
    @POST
    public Response insertGebruiker(String gebruiker) {
        try {
            int aantal;
            Gebruiker newG = g.fromJson(gebruiker, Gebruiker.class);
            PasswordEncryptionService encryptor = new PasswordEncryptionService();

            CallableStatement s = con.prepareCall("CALL insertGebruiker(?,?,?,?,?,?)");
            s.setString(1, newG.getVoornaam());
            s.setString(2, newG.getAchternaam());
            s.setString(3, newG.getGeboortedatum());
            byte[] salt = encryptor.generateSalt();
            s.setBytes(4, encryptor.getEncryptedPassword(newG.getWachtwoord_hash(), salt));
            s.setBytes(5, salt);
            s.setString(6, newG.getEmail());

            aantal = s.executeUpdate();
            if (aantal == 1) {
                return Response.status(Response.Status.OK).build();
            }
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return Response.status(Response.Status.CONFLICT).build();
    }

    @Path("/aankoop")
    @Consumes(MediaType.APPLICATION_JSON)
    @POST
    public Response buyFilm(String aankoop) {
        try {
            Aankoop a = g.fromJson(aankoop, Aankoop.class);

            CallableStatement s = con.prepareCall("CALL buyFilm(?,?)");
            s.setString(1, a.getGebruiker_ID());
            s.setString(2, a.getFilm_ID());
            
            int aantal; 
            aantal = s.executeUpdate();
            
            if(aantal == 1) {
                return Response.status(Response.Status.OK).build();
            } else {
                return Response.status(Response.Status.PRECONDITION_FAILED).build();
            }
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return Response.status(Response.Status.CONFLICT).build();
    }

    @Path("/commentaar")
    @Consumes(MediaType.APPLICATION_JSON)
    @POST
    public String insertCommentaar(String commentaar) {
        try {
            Commentaar c = g.fromJson(commentaar, Commentaar.class);

            CallableStatement s = con.prepareCall("CALL insertCommentaar(?,?,?)");

            s.setString(0, c.getGebruiker_ID());
            s.setString(1, c.getFilm_ID());
            s.setString(3, c.getCommentaar());

            s.executeUpdate();
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return "Error";
    }

    @Path("/login")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public String login(@QueryParam("email") String email, @QueryParam("ww") String ww) {
        try {
            ResultSet rs;
            PasswordEncryptionService encryptor = new PasswordEncryptionService();

            CallableStatement s = con.prepareCall("CALL login(?)");
            s.setString(1, email);

            rs = s.executeQuery();

            if (rs.next()) {
                byte[] hash = rs.getBytes("Wachtwoord_hash");
                byte[] salt = rs.getBytes("Salt");

                boolean succces = encryptor.authenticate(ww, hash, salt);

                if (succces) {
                    Gebruiker gebruiker = new Gebruiker();
                    gebruiker.setGebruiker_ID(rs.getString("Gebruiker_ID"));
                    gebruiker.setVoornaam(rs.getString("Voornaam"));
                    gebruiker.setAchternaam(rs.getString("Achternaam"));
                    gebruiker.setEmail(rs.getString("Email"));
                    gebruiker.setGeboortedatum(rs.getString("Geboortedatum"));

                    return g.toJson(gebruiker);
                }
            }
        } catch (Exception e) {
            Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                con.close();
            } catch (SQLException ex) {
                Logger.getLogger(RESTResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return "False";
    }
}
